package productConfig

import (
	"context"
	"devops-super/api"
	"devops-super/api/configs/v1"
	"devops-super/internal/consts/cacheConsts"
	"devops-super/internal/dao"
	"devops-super/internal/model/entity"
	"devops-super/internal/service"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
)

// sProductConfig 产品配置逻辑实现
type sProductConfig struct{}

func init() {
	service.RegisterProductConfig(New())
}

// New 创建产品配置逻辑实例
func New() *sProductConfig {
	return &sProductConfig{}
}

// GetPageLst 分页获取产品配置列表
func (*sProductConfig) GetPageLst(ctx context.Context, in *v1.ProductConfigGetPageLstReq) (out *api.PageLstRes[*entity.AppProductConfig], err error) {
	out = &api.PageLstRes[*entity.AppProductConfig]{}
	m := dao.AppProductConfig.Ctx(ctx).Safe(true)

	// 产品ID筛选
	if in.ProductId > 0 {
		m = m.Where(dao.AppProductConfig.Columns().ProductId, in.ProductId)
	}

	// 配置组名筛选
	if in.GroupName != "" {
		m = m.Where(dao.AppProductConfig.Columns().GroupName+" like ?", "%"+in.GroupName+"%")
	}

	// 分页查询
	if out.Total, err = m.Count(); err != nil {
		return
	}
	if out.Total == 0 {
		out.List = []*entity.AppProductConfig{}
		return
	}

	// 执行查询
	if err = m.Offset(in.Offset()).Limit(in.Limit()).OrderDesc(dao.AppProductConfig.Columns().Id).Scan(&out.List); err != nil {
		return
	}

	return
}

// Add 新增产品配置
func (*sProductConfig) Add(ctx context.Context, in *entity.AppProductConfig) (err error) {
	// 检查配置是否已存在 (产品+组名+配置键唯一)
	count, err := dao.AppProductConfig.Ctx(ctx).Where(g.Map{
		dao.AppProductConfig.Columns().ProductId: in.ProductId,
		dao.AppProductConfig.Columns().GroupName: in.GroupName,
		dao.AppProductConfig.Columns().ConfigKey: in.ConfigKey,
	}).Count()
	if err != nil {
		return err
	}
	if count > 0 {
		return errors.New("该产品下的配置组和配置键已存在")
	}

	// 插入记录
	_, err = dao.AppProductConfig.Ctx(ctx).Insert(in)
	return
}

// Upt 更新产品配置
func (*sProductConfig) Upt(ctx context.Context, in *entity.AppProductConfig) (err error) {
	// 检查配置是否存在
	oldConfig := &entity.AppProductConfig{}
	err = dao.AppProductConfig.Ctx(ctx).WherePri(in.Id).Scan(oldConfig)
	if err != nil {
		return err
	}
	if oldConfig.Id == 0 {
		return errors.New("配置不存在")
	}

	// 检查是否修改了唯一键字段，如果修改则需要检查唯一性
	if oldConfig.ProductId != in.ProductId || oldConfig.GroupName != in.GroupName ||
		oldConfig.ConfigKey != in.ConfigKey {

		count, err := dao.AppProductConfig.Ctx(ctx).Where(g.Map{
			dao.AppProductConfig.Columns().ProductId: in.ProductId,
			dao.AppProductConfig.Columns().GroupName: in.GroupName,
			dao.AppProductConfig.Columns().ConfigKey: in.ConfigKey,
			dao.AppProductConfig.Columns().Id:        in.Id,
		}).Count()
		if err != nil {
			return err
		}
		if count > 0 {
			return errors.New("该产品下的配置组和配置键已存在")
		}
	}

	// 更新记录
	_, err = dao.AppProductConfig.Ctx(ctx).WherePri(in.Id).OmitNilData().Data(in).Update()
	return
}

// Del 删除产品配置
func (*sProductConfig) Del(ctx context.Context, id int64) (err error) {
	// 先查询配置信息
	config := &entity.AppProductConfig{}
	err = dao.AppProductConfig.Ctx(ctx).WherePri(id).Scan(config)
	if err != nil || config.Id == 0 {
		return errors.New("配置不存在")
	}
	// 删除缓存
	cacheKey := cacheConsts.GetProductConfigKey(config.ProductId, config.GroupName, config.ConfigKey)
	_, _ = service.GetCacheInstance().Remove(ctx, cacheKey)
	// 删除数据库记录
	_, err = dao.AppProductConfig.Ctx(ctx).WherePri(id).Delete()
	return err
}

// GetOne 获取单条产品配置
func (*sProductConfig) GetOne(ctx context.Context, id int64) (out *entity.AppProductConfig, err error) {
	out = &entity.AppProductConfig{}
	err = dao.AppProductConfig.Ctx(ctx).WherePri(id).Scan(out)
	return
}

// GetOptions 获取产品配置选项
func (*sProductConfig) GetOptions(ctx context.Context, in *v1.ProductConfigGetOptionsReq) (out *v1.ProductConfigGetOptionsRes, err error) {
	m := dao.AppProductConfig.Ctx(ctx).Safe(true)

	// 产品ID筛选
	if in.ProductId > 0 {
		m = m.Where(dao.AppProductConfig.Columns().ProductId, in.ProductId)
	}

	// 查询数据
	var data []*entity.AppProductConfig
	if err = m.Scan(&data); err != nil {
		return
	}

	// 构建选项列表
	out = new(v1.ProductConfigGetOptionsRes)
	out.Options = make([]*api.FormOptionsItem, 0, len(data))

	// 默认value和label字段
	valueField := "id"
	labelField := "configKey"
	if in.FieldKey != "" {
		valueField = in.FieldKey
	}
	if in.FieldLabel != "" {
		labelField = in.FieldLabel
	}

	for _, item := range data {
		option := &api.FormOptionsItem{}
		// 设置value
		switch valueField {
		case "id":
			option.Value = item.Id
		case "configKey":
			option.Value = item.ConfigKey
		case "groupName":
			option.Value = item.GroupName
		default:
			option.Value = item.Id
		}

		// 设置label
		switch labelField {
		case "configKey":
			option.Label = item.ConfigKey
		case "groupName":
			option.Label = item.GroupName
		case "configValue":
			option.Label = item.ConfigValue
		default:
			option.Label = item.ConfigKey
		}

		out.Options = append(out.Options, option)
	}

	return
}

// GetGroupConfigs 获取配置组
func (*sProductConfig) GetGroupConfigs(ctx context.Context, in *v1.GetProductGroupConfigsReq) (out *v1.GetProductGroupConfigsRes, err error) {
	out = &v1.GetProductGroupConfigsRes{}

	// 查询配置项
	err = dao.AppProductConfig.Ctx(ctx).
		Where(dao.AppProductConfig.Columns().ProductId, in.ProductId).
		Where(dao.AppProductConfig.Columns().GroupName, in.GroupName).
		Order(dao.AppProductConfig.Columns().Id).
		Scan(&out.Configs)
	if err != nil {
		return nil, err
	}

	// 获取最新更新时间
	if len(out.Configs) > 0 {
		latestTime := out.Configs[0].UpdatedAt
		for _, item := range out.Configs {
			if item.UpdatedAt.After(latestTime) {
				latestTime = item.UpdatedAt
			}
		}
		out.UpdatedAt = latestTime.Format("2006-01-02 15:04:05")
	}

	return out, nil
}

// SetGroupConfigs 保存配置组
func (*sProductConfig) SetGroupConfigs(ctx context.Context, in *v1.SetProductGroupConfigsReq) (err error) {
	// 使用事务确保数据一致性
	tx, err := g.DB().Begin(ctx)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	// 删除产品下指定组的现有配置
	_, err = dao.AppProductConfig.Ctx(ctx).
		TX(tx).
		Where(dao.AppProductConfig.Columns().ProductId, in.ProductId).
		Where(dao.AppProductConfig.Columns().GroupName, in.GroupName).
		Delete()
	if err != nil {
		return err
	}

	// 批量添加新配置
	for _, item := range in.Configs {
		// 唯一性校验
		exists, err := dao.AppProductConfig.Ctx(ctx).
			TX(tx).
			Where(g.Map{
				dao.AppProductConfig.Columns().ProductId: in.ProductId,
				dao.AppProductConfig.Columns().GroupName: in.GroupName,
				dao.AppProductConfig.Columns().ConfigKey: item.ConfigKey,
			}).Count()
		if err != nil {
			return err
		}
		if exists > 0 {
			return errors.New(fmt.Sprintf("配置键 %s 已存在", item.ConfigKey))
		}

		// 插入新配置
		_, err = dao.AppProductConfig.Ctx(ctx).TX(tx).Insert(&entity.AppProductConfig{
			ProductId:   int64(in.ProductId),
			GroupName:   in.GroupName,
			ConfigKey:   item.ConfigKey,
			ConfigValue: item.ConfigValue,
			Remark:      item.ConfigDesc,
			CreatedAt:   gtime.Now(),
			UpdatedAt:   gtime.Now(),
		})
		if err != nil {
			return err
		}
		cacheKey := cacheConsts.GetProductConfigKey(int64(in.ProductId), in.GroupName, item.ConfigKey)
		_ = service.GetCacheInstance().Set(ctx, cacheKey, item.ConfigValue, 0)
	}

	return nil
}

// GetConfigByKey 根据产品ID、分组名和键名获取配置（优先从缓存读取）
func (*sProductConfig) GetConfigByKey(ctx context.Context, productId int64, groupName, configKey string) (configValue string, err error) {
	// 生成缓存键
	cacheKey := cacheConsts.GetProductConfigKey(productId, groupName, configKey)

	// 先从缓存读取
	if v, err := service.GetCacheInstance().Get(ctx, cacheKey); err == nil && !v.IsEmpty() {
		return v.String(), nil
	}

	// 缓存不存在则从数据库读取
	config := new(entity.AppProductConfig)
	err = dao.AppProductConfig.Ctx(ctx).
		Where(dao.AppProductConfig.Columns().ProductId, productId).
		Where(dao.AppProductConfig.Columns().GroupName, groupName).
		Where(dao.AppProductConfig.Columns().ConfigKey, configKey).
		Scan(&config)

	if err != nil || config.Id == 0 {
		return "", errors.New("配置不存在")
	}

	// 设置缓存
	_ = service.GetCacheInstance().Set(ctx, cacheKey, config.ConfigValue, 0)

	return config.ConfigValue, nil
}
